package cn.walket.cloud.user.db;

import static java.util.Arrays.asList;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import java.util.Arrays;
import javax.sql.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

/**
 * @Author walket
 * @create 2021/2/1 5:17 下午
 */
@Slf4j
@EnableTransactionManagement
@EnableConfigurationProperties
@Configuration
public class DaoConfig implements TransactionManagementConfigurer {

  @Autowired
  @Qualifier("userTxManager")
  private PlatformTransactionManager platformTransactionManager;

  /**
   * FIXME SQL 合并告警 参考IPCDruidDataSourceStatLoggerImpl
   * @param dsConfig
   * @return
   * @throws Exception
   */
  @Bean(name = "userDataSource", initMethod = "init", destroyMethod = "close")
  public DataSource userDataSource(cn.walket.cloud.user.db.DatasourceProperties dsConfig)
      throws Exception {
    if (log.isDebugEnabled()) {
      log.debug("{} ", dsConfig);
    }
    log.info("{}", dsConfig);
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setName("user");
    dataSource.setUrl(dsConfig.getUrl());
    dataSource.setUsername(dsConfig.getUsername());
//   DruidPasswordCallback druidPasswordCallback = new druidPasswordCallback();
//    druidPasswordCallback.setPassword(dsConfig.getPassword().toCharArray());
//    druidPasswordCallback.setAppPrivateKeyFilePath("classpath:key_app_pri.pem");
//    druidPasswordCallback.setSysPublicKeyFilePath("classpath:key_sys_pub.pem");
//    dataSource.setPasswordCallback(druidPasswordCallback);
    dataSource.setPassword(dsConfig.getPassword());
    dataSource.setInitialSize(dsConfig.getInitialSize());
    dataSource.setMinIdle(dsConfig.getMinIdle());
    dataSource.setMaxActive(dsConfig.getMaxActive());
    dataSource.setMaxWait(dsConfig.getMaxWait());
    dataSource.setTimeBetweenEvictionRunsMillis(dsConfig.getTimeBetweenEvictionRunsMillis());
    dataSource.setMinEvictableIdleTimeMillis(dsConfig.getMinEvictableIdleTimeMillis());
    dataSource.setTimeBetweenEvictionRunsMillis(60000);
    dataSource.setFilters("slf4j");
    dataSource.setValidationQuery("SELECT 1");
    dataSource.setTestWhileIdle(true);
    dataSource.setTestOnReturn(false);
    dataSource.setTestOnBorrow(false);
    dataSource.setPoolPreparedStatements(false);
    SlowSqlStatFilter statFilter = new SlowSqlStatFilter(50L,true,true);
    dataSource.setProxyFilters(asList(statFilter));
    return dataSource;
  }

  @Bean(name = "userSqlSessionFactory")
  public SqlSessionFactory userSqlSessionFactory(@Qualifier("userDataSource") DataSource datasource)
      throws Exception {
    MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
    bean.setDataSource(datasource);
    GlobalConfig defaults = GlobalConfigUtils.defaults();
    DbConfig dbConfig = defaults.getDbConfig();
    if (dbConfig == null) {
      dbConfig = new DbConfig();
      dbConfig.setIdType(IdType.NONE);
      defaults.setDbConfig(dbConfig);
    } else {
      dbConfig.setIdType(IdType.NONE);
    }
    bean.setGlobalConfig(defaults);
    ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
    Resource[] mappersResources = resourceResolver.getResources("classpath*:mapper/user/*Mapper.xml");
    log.debug("scan {}", Arrays.toString(mappersResources));
    bean.setMapperLocations(mappersResources);
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    bean.setPlugins(interceptor);
    MybatisConfiguration configuration = bean.getConfiguration();
    if (configuration == null) {
      configuration = new MybatisConfiguration();
      bean.setConfiguration(configuration);
    }
    configuration.setUseDeprecatedExecutor(false);
    return bean.getObject();
  }

  @Bean("userSqlSessionTemplate")
  public SqlSessionTemplate userSqlSessionTemplate(SqlSessionFactory sessionfactory) {
    return new SqlSessionTemplate(sessionfactory);
  }

  @Bean("userMapperScannerConfigurer")
  public MapperScannerConfigurer userMapperScannerConfigurer() {
    MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
    mapperScannerConfigurer.setSqlSessionFactoryBeanName("userSqlSessionFactory");
    mapperScannerConfigurer.setSqlSessionTemplateBeanName("userSqlSessionTemplate");
    mapperScannerConfigurer.setBasePackage("cn.walket.cloud.user");
    return mapperScannerConfigurer;
  }

  @Primary
  @Bean("userTxManager")
  public PlatformTransactionManager txManager(@Qualifier("userDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }

  @Override
  public PlatformTransactionManager annotationDrivenTransactionManager() {
    return platformTransactionManager;
  }
}